
from threading import Thread, Lock
from queue import Queue, Empty
from collections import defaultdict
from SimTrader.objects import Event


class EventEngine:
    def __init__(self):
        """
        实例化一个事件引擎对象
        """
        # 事件:处理函数映射表 {event_type: [handle1, handle2]}
        self.__event_handles_dict = defaultdict(list)
        self.__thead = Thread(target=self.__run)
        # 事件队列，用于线程间通信
        self.__queue = Queue()
        # handler 锁
        self.__hd_lock = Lock()
        # register 锁
        self.__rg_lock = Lock()
        # 启动线程标志
        self.__active = False

    def activate_thread(self):
        self.__active = True

    def terminate_thread(self):
        self.__active = False

    def start(self):
        self.__thead.start()

    def __run(self):
        while self.__active:
            try:
                event = self.__queue.get(block=True, timeout=0.5)
                self.__process(event)
            except Empty:
                pass

    def put(self, event: Event):
        self.__rg_lock.acquire()
        self.__queue.put(event)
        self.__rg_lock.release()

    def __process(self, event: Event):
        self.__hd_lock.acquire()
        if event.type in self.__event_handles_dict:
            [handler(event.data) for handler in self.__event_handles_dict[event.type]]
        self.__hd_lock.release()

    def register(self, event_type, handler):
        self.__rg_lock.acquire()
        self.__event_handles_dict[event_type].append(handler)
        self.__rg_lock.release()

    def unregister(self, event_type, handler):
        self.__rg_lock.acquire()
        if handler in self.__event_handles_dict[event_type]:
            self.__event_handles_dict[event_type].remove(handler)
        if len(self.__event_handles_dict[event_type]) == 0:
            self.__event_handles_dict.pop(event_type)
        self.__rg_lock.release()